#!/usr/bin/env bash
set -euo pipefail

### ========= 基本配置（可用环境变量覆盖） =========
APP_NAME="universal-official-website"
APP_USER="${APP_USER:-webapp}"
APP_GROUP="$APP_USER"
APP_DIR="/opt/${APP_NAME}"
APP_ENV="${APP_DIR}/venv"
APP_RUN_DIR="/run/${APP_NAME}"
LOG_DIR="/var/log/${APP_NAME}"

ROOT_DOMAIN="${ROOT_DOMAIN:-szboat.com}"
WWW_DOMAIN="${WWW_DOMAIN:-www.szboat.com}"
EMAIL_LETSENCRYPT="${EMAIL_LETSENCRYPT:-admin@${ROOT_DOMAIN}}"
ENABLE_SSL="${ENABLE_SSL:-yes}"

GIT_REPO="${GIT_REPO:-https://zack_lam:b7a49f8a4f6f7b3c94872e02022d5d77@gitee.com/zack_lam/universal-official-website.git}"
GIT_BRANCH="${GIT_BRANCH:-main}"
PYTHON_BIN="${PYTHON_BIN:-python3}"
FLASK_APP_FILE="${FLASK_APP_FILE:-manage.py}"  # 你的 Flask 入口文件

# ==== MySQL 初始化配置（强烈建议传入安全密码） ====
DB_HOST="${DB_HOST:-127.0.0.1}"
DB_PORT="${DB_PORT:-3306}"
DB_NAME="${DB_NAME:-${APP_NAME}}"
DB_USER="${DB_USER:-${APP_NAME}}"
DB_PASS="${DB_PASS:-ChangeMe_$(openssl rand -hex 6)}"

# .env 默认值（部署后你可手动修改）
DB_URL_DEFAULT="mysql+pymysql://${DB_USER}:${DB_PASS}@${DB_HOST}:${DB_PORT}/${DB_NAME}?charset=utf8mb4"

### ========= 工具函数 =========
log(){ echo -e "\033[1;32m[DEPLOY]\033[0m $*"; }
warn(){ echo -e "\033[1;33m[WARN]\033[0m $*"; }
err(){ echo -e "\033[1;31m[ERROR]\033[0m $*"; exit 1; }

detect_os() {
  if [ -f /etc/os-release ]; then . /etc/os-release; echo "$ID"; else echo "$(uname -s)"; fi
}

open_firewall() {
  local osid; osid="$(detect_os)"
  if command -v ufw >/dev/null 2>&1; then
    ufw allow 80/tcp || true
    ufw allow 443/tcp || true
  elif command -v firewall-cmd >/dev/null 2>&1; then
    firewall-cmd --permanent --add-service=http || true
    firewall-cmd --permanent --add-service=https || true
    firewall-cmd --reload || true
  else
    log "No firewall tool detected, skipping port open."
  fi
}

install_packages() {
  local osid; osid="$(detect_os)"
  log "Installing system packages on ${osid}..."
  if [[ "$osid" == "ubuntu" || "$osid" == "debian" ]]; then
    apt-get update
    DEBIAN_FRONTEND=noninteractive apt-get install -y \
      python3 python3-venv python3-pip python3-dev build-essential \
      default-libmysqlclient-dev pkg-config \
      nginx git unzip curl redis-server \
      mysql-server \
      certbot python3-certbot-nginx
    systemctl enable redis-server || true
    systemctl enable mysql || true
    systemctl start mysql || true
  else
    yum -y install epel-release || true
    yum -y install python3 python3-venv python3-pip python3-devel gcc gcc-c++ make \
      mysql mysql-server mariadb-devel \
      nginx git unzip curl redis \
      certbot python3-certbot-nginx || true
    systemctl enable redis || true
    systemctl enable mysqld || systemctl enable mariadb || true
    systemctl start mysqld || systemctl start mariadb || true
  fi
}

init_mysql() {
  log "Initializing MySQL (DB=${DB_NAME}, USER=${DB_USER}) ..."
  # 尝试用 socket 或无密码方式连接（常见在新装 MySQL）
  local SQL_CREATE="
CREATE DATABASE IF NOT EXISTS \`${DB_NAME}\` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER IF NOT EXISTS '${DB_USER}'@'%' IDENTIFIED BY '${DB_PASS}';
GRANT ALL PRIVILEGES ON \`${DB_NAME}\`.* TO '${DB_USER}'@'%';
FLUSH PRIVILEGES;
"
  # 适配不同系统命令名
  local MYSQL_BIN="mysql"
  command -v mysql >/dev/null 2>&1 || err "mysql client not found"

  # 多尝试几种连接方式（socket / root 空密 / mariadb）
  if $MYSQL_BIN -uroot -e "SELECT 1" >/dev/null 2>&1; then
    echo "$SQL_CREATE" | $MYSQL_BIN -uroot
  elif $MYSQL_BIN -uroot -p"" -e "SELECT 1" >/dev/null 2>&1; then
    echo "$SQL_CREATE" | $MYSQL_BIN -uroot -p""
  elif $MYSQL_BIN --protocol=SOCKET -uroot -e "SELECT 1" >/dev/null 2>&1; then
    echo "$SQL_CREATE" | $MYSQL_BIN --protocol=SOCKET -uroot
  else
    warn "Cannot auth MySQL root automatically. Please run the following SQL manually:\n$SQL_CREATE"
  fi
}

create_user_and_dirs() {
  log "Creating user and directories..."
  id -u "$APP_USER" >/dev/null 2>&1 || useradd -r -m -d "/home/${APP_USER}" -s /usr/sbin/nologin "$APP_USER"
  mkdir -p "$APP_DIR" "$APP_RUN_DIR" "$LOG_DIR"
  chown -R "${APP_USER}:${APP_GROUP}" "$APP_DIR" "$APP_RUN_DIR" "$LOG_DIR"
}

deploy_code() {
  log "Deploying code from Git: ${GIT_REPO} (branch ${GIT_BRANCH}) ..."
  if [ -d "${APP_DIR}/.git" ]; then
    sudo -u "$APP_USER" -H git -C "$APP_DIR" fetch --all
    sudo -u "$APP_USER" -H git -C "$APP_DIR" checkout "$GIT_BRANCH"
    sudo -u "$APP_USER" -H git -C "$APP_DIR" pull --rebase origin "$GIT_BRANCH"
  else
    rm -rf "$APP_DIR"/* || true
    sudo -u "$APP_USER" -H git clone -b "$GIT_BRANCH" "$GIT_REPO" "$APP_DIR"
  fi
}

create_venv_and_install() {
  log "Creating venv and installing requirements ..."
  sudo -u "$APP_USER" -H bash -c "
    cd '$APP_DIR' && ${PYTHON_BIN} -m venv '$APP_ENV' && \
    source '$APP_ENV/bin/activate' && \
    pip install --upgrade pip wheel && \
    if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
  "
}

ensure_env_file() {
  log "Ensuring .env exists ..."
  if [ ! -f "${APP_DIR}/.env" ]; then
cat > "${APP_DIR}/.env" <<EOF
# ====== Flask / App ======
FLASK_ENV=production
FLASK_APP=${FLASK_APP_FILE}
SECRET_KEY=$(openssl rand -hex 32)

# ====== Database ======
DATABASE_URL=${DB_URL_DEFAULT}
SQLALCHEMY_DATABASE_URI=\${DATABASE_URL}

# ====== PayPal ======
PAYPAL_ENV=sandbox
PAYPAL_CLIENT_ID=your_client_id
PAYPAL_SECRET=your_secret

# ====== Misc ======
DOMAIN=${WWW_DOMAIN}
REDIS_URL=redis://127.0.0.1:6379/0
EOF
    chown "${APP_USER}:${APP_GROUP}" "${APP_DIR}/.env"
    log "Created ${APP_DIR}/.env (已写入 DB_URL、域名、PayPal 占位)"
  else
    # 保持 .env 里已有的自定义内容
    sed -i "s|^DOMAIN=.*|DOMAIN=${WWW_DOMAIN}|g" "${APP_DIR}/.env" || true
  fi
}

run_migrations() {
  log "Running Alembic migrations ..."
  sudo -u "$APP_USER" -H bash -c "
    set -e
    cd '$APP_DIR'
    source '$APP_ENV/bin/activate'
    export FLASK_APP='${FLASK_APP_FILE}'
    export \$(grep -v '^#' .env | xargs -I{} echo {})
    flask db upgrade
  "
}

write_systemd_units() {
  log "Writing systemd units ..."
  cat > "/etc/systemd/system/${APP_NAME}.service" <<EOF
[Unit]
Description=${APP_NAME} Gunicorn Service
After=network.target

[Service]
Type=simple
User=${APP_USER}
Group=${APP_GROUP}
WorkingDirectory=${APP_DIR}
EnvironmentFile=${APP_DIR}/.env
ExecStart=${APP_ENV}/bin/gunicorn --workers 3 --bind unix:${APP_RUN_DIR}/${APP_NAME}.sock wsgi:app
Restart=always
RuntimeDirectory=${APP_NAME}

[Install]
WantedBy=multi-user.target
EOF

  cat > "/etc/systemd/system/${APP_NAME}-celery.service" <<EOF
[Unit]
Description=${APP_NAME} Celery Worker
After=network.target

[Service]
Type=simple
User=${APP_USER}
Group=${APP_GROUP}
WorkingDirectory=${APP_DIR}
EnvironmentFile=${APP_DIR}/.env
ExecStart=${APP_ENV}/bin/celery -A app.celery_app worker --loglevel=INFO
Restart=always

[Install]
WantedBy=multi-user.target
EOF

  cat > "/etc/systemd/system/${APP_NAME}-beat.service" <<EOF
[Unit]
Description=${APP_NAME} Celery Beat
After=network.target

[Service]
Type=simple
User=${APP_USER}
Group=${APP_GROUP}
WorkingDirectory=${APP_DIR}
EnvironmentFile=${APP_DIR}/.env
ExecStart=${APP_ENV}/bin/celery -A app.celery_app beat --loglevel=INFO
Restart=always

[Install]
WantedBy=multi-user.target
EOF

  mkdir -p "$APP_RUN_DIR"
  chown -R "${APP_USER}:${APP_GROUP}" "$APP_RUN_DIR"

  systemctl daemon-reload
  systemctl enable "${APP_NAME}.service" "${APP_NAME}-celery.service" "${APP_NAME}-beat.service"
}

write_nginx() {
  log "Writing NGINX config (www + 裸域301) ..."
  cat > "/etc/nginx/sites-available/${APP_NAME}" <<EOF
# 裸域 80 → 301 到 www
server {
    listen 80;
    server_name ${ROOT_DOMAIN};
    return 301 http://${WWW_DOMAIN}\$request_uri;
}

# 主站（www）80 → 反代到 gunicorn（证书签好后 certbot 会自动改 HTTPS）
server {
    listen 80;
    server_name ${WWW_DOMAIN};
    client_max_body_size 32m;

    access_log ${LOG_DIR}/nginx_access.log;
    error_log  ${LOG_DIR}/nginx_error.log;

    location / {
        include proxy_params;
        proxy_pass http://unix:${APP_RUN_DIR}/${APP_NAME}.sock;
        proxy_read_timeout 300;
    }
    # location /static/ { alias ${APP_DIR}/static/; expires 7d; }
}
EOF

  ln -sf "/etc/nginx/sites-available/${APP_NAME}" "/etc/nginx/sites-enabled/${APP_NAME}" || true
  nginx -t
  systemctl restart nginx
}

enable_ssl() {
  if [[ "${ENABLE_SSL}" == "yes" ]]; then
    log "Requesting HTTPS for ${WWW_DOMAIN} and ${ROOT_DOMAIN} ..."
    certbot --nginx -d "${WWW_DOMAIN}" -d "${ROOT_DOMAIN}" \
      -m "${EMAIL_LETSENCRYPT}" --agree-tos --non-interactive || warn "Certbot failed"

    # 追加 裸域 443 → 301 到 www（避免直连 https://szboat.com）
    if ! grep -q "listen 443 ssl http2;" "/etc/nginx/sites-available/${APP_NAME}" 2>/dev/null; then
      cat >> "/etc/nginx/sites-available/${APP_NAME}" <<EOF

# 裸域 443 → 301 到 https://www
server {
    listen 443 ssl http2;
    server_name ${ROOT_DOMAIN};
    return 301 https://${WWW_DOMAIN}\$request_uri;
}
EOF
    fi

    # 可选：为主站块加 HSTS（只在确认 HTTPS OK 后打开）
    if ! grep -q "Strict-Transport-Security" "/etc/nginx/sites-available/${APP_NAME}"; then
      sed -i '/server_name '"${WWW_DOMAIN}"'.*;/a \    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;' "/etc/nginx/sites-available/${APP_NAME}" || true
    fi

    nginx -t && systemctl reload nginx
  else
    log "ENABLE_SSL=no -> Skipping certbot. You can enable later by rerunning."
  fi
}

setup_logrotate() {
  log "Configuring logrotate ..."
  cat > "/etc/logrotate.d/${APP_NAME}" <<EOF
${LOG_DIR}/*.log {
    daily
    missingok
    rotate 14
    compress
    delaycompress
    notifempty
    create 0640 ${APP_USER} ${APP_GROUP}
    sharedscripts
    postrotate
        systemctl reload nginx >/dev/null 2>&1 || true
    endscript
}
EOF
}

start_services() {
  log "Starting services ..."
  systemctl restart "${APP_NAME}.service"
  systemctl restart "${APP_NAME}-celery.service" || true
  systemctl restart "${APP_NAME}-beat.service" || true
  systemctl status "${APP_NAME}.service" --no-pager || true
}

### ========= 主流程 =========
open_firewall
install_packages
init_mysql
create_user_and_dirs
deploy_code
create_venv_and_install
ensure_env_file
write_systemd_units
write_nginx
setup_logrotate
enable_ssl
# 迁移放在 HTTPS 后也行，但通常先升级 DB 再上线进程：
run_migrations
start_services

log "✅ Done. Visit: https://${WWW_DOMAIN}  （szboat.com 将 301 → www）"
log "   DB: ${DB_NAME}, USER: ${DB_USER}, PASS: ${DB_PASS}  （已写入 .env）"
log "   修改配置：${APP_DIR}/.env   重启：systemctl restart ${APP_NAME}"
